#include "PhidgetRootObject.h"
#include "PhidgetValueObject.h"
#include "Phidget.h"
#include "PhidgetManager.h"
#include "PhidgetPropertyAlias.h"
#include "MonkeyEventCallback.h"
#include "Message.h"
#include "MessageCenter.h"
#include <stdexcept>


//
// Define the class information for the JS object.
//
static JSClass object_class = {
    "Phidget", JSCLASS_HAS_PRIVATE,
    JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
    JSCLASS_NO_OPTIONAL_MEMBERS
};



//
// Create the new root Phidget object.
//
PhidgetRootObject::PhidgetRootObject(PhidgetManager *pm, MonkeyRuntime *rt)
{
	//
	// Save the manager for later use.
	//
	manager = pm;
	
	//
	// Create child objects.
	//
	valueObject = new PhidgetValueObject(pm, rt);
}


//
// Destroy the object and free memory.
//
PhidgetRootObject::~PhidgetRootObject()
{
	delete valueObject;
	valueObject = NULL;
}


//
// Register this object with the parent object.
//
void PhidgetRootObject::RegisterObject(MonkeyContext *ctx, JSObject *parent)
{
	MonkeyObject::RegisterObject(ctx, parent);

	JS_BeginRequest(Context()->jsContext());
	object = JS_DefineObject(Context()->jsContext(), parent, "phidget", &object_class, NULL, (JSPROP_READONLY | JSPROP_PERMANENT));
	JS_SetPrivate(Context()->jsContext(), object, this);
    JS_DefineFunction(Context()->jsContext(), object, "onvaluechange", PhidgetRootObject::js_onvaluechange, 2, 0);
	JS_EndRequest(Context()->jsContext());
	
	//
	// Register child objects.
	//
	AddObject(valueObject);
}


//
// An event callback should be triggered. Call the javascript function.
//
void PhidgetRootObject::jscb_event(Message *msg, void *userInfo)
{
	MonkeyEventCallback *cb = (MonkeyEventCallback *)userInfo;
	JSContext *cx = cb->getContext();
	jsval rval, args[2];
	std::string value = msg->getUserInfo()["newValue"];


	JS_BeginRequest(cx);
	args[0] = STRING_TO_JSVAL(JS_NewStringCopyN(cx, cb->getEventName().c_str(), cb->getEventName().size()));
	args[1] = STRING_TO_JSVAL(JS_NewStringCopyN(cx, value.c_str(), value.size()));
	JS_CallFunctionValue(cx, JS_GetGlobalObject(cx), cb->getCallback(), 2, args, &rval);
	JS_EndRequest(cx);
}


//
// Register to receive a callback event when the given notification happens.
//
JSBool PhidgetRootObject::js_onvaluechange(JSContext *cx, uintN argc, jsval *vp)
{
	if (argc == 2 && JS_TypeOfValue(cx, JS_ARGV(cx, vp)[1]) == JSTYPE_FUNCTION)
	{
		MonkeyEventCallback *cb;
		const char *name;
		jsval func;

		name = JS_EncodeString(cx, JS_ValueToString(cx, JS_ARGV(cx, vp)[0]));
		JS_ConvertValue(cx, JS_ARGV(cx, vp)[1], JSTYPE_FUNCTION, &func);
		cb = new MonkeyEventCallback(std::string(name), cx, func);
		MessageCenter::SharedMessageCenter().AddObserver(std::string(name), jscb_event, cb);

		return JS_TRUE;
	}
	
	return JS_FALSE;
}


